package com.example.speeddating.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.example.speeddating.algorithm.AlgorithmUtils;
import com.example.speeddating.algorithm.CosineSimilarityUtil;
import com.example.speeddating.common.BaseResponse;
import com.example.speeddating.constants.Constants;
import com.example.speeddating.constants.TaoHuaConstant;
import com.example.speeddating.dto.MatchDto;
import com.example.speeddating.dto.UserCommentLikeDTO;
import com.example.speeddating.entity.*;
import com.example.speeddating.enums.ResponseCodeEnum;
import com.example.speeddating.exception.CommonException;
import com.example.speeddating.mapper.*;
import com.example.speeddating.service.*;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.example.speeddating.tool.StringTools;
import com.example.speeddating.utils.SecretUtil;
import com.google.gson.Gson;
import com.google.gson.reflect.TypeToken;
//import jakarta.persistence.criteria.CriteriaBuilder;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.math3.util.Pair;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.text.SimpleDateFormat;
import java.util.*;
import java.util.stream.Collectors;

/**
 *
 * @author tina
 * @since 2023-06-28 11:14:34
 */
@Slf4j
@Service
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements UserService {

    @Value("${soulmate.avatar}")
    private String defaultAvatar;

    @Autowired
    private UserMapper userMapper;

    @Autowired
    private LikeMapper likeMapper;

    @Autowired
    private ArticleMapper articleMapper;

    @Autowired
    private CommentMapper commentMapper;

    @Autowired
    private MatchMapper matchMapper;

    @Autowired
    private TagsService tagsService;

    @Autowired
    private EmailCodeService emailCodeService;

    @Autowired
    private TaohuaDetailService taohuaDetailService;

    @Autowired
    private AutheticInfoService autheticInfoService;

    @Autowired
    private PreferenceService preferenceService;

    @Autowired
    private MatchService matchService;

    @Autowired
    private MessageService messageService;

    @Autowired
    private BulletMapper bulletMapper;

    @Override
    public User selectByUserId(Long userId,Long curUser) {

        User user = userMapper.selectByUserId(userId);
        if (curUser.equals(userId))return user;
        Integer focus = userMapper.selectIsFocus(curUser,userId);//查询是否关注发布文章的user
        if (focus != 0) {
            user.setIsFollowed(true);
        } else {
            user.setIsFollowed(false);
        }
        return user;
    }

    @Override
    public User selectByUserId(Long userId) {
        AutheticInfo autheticInfo = autheticInfoService.selectAutheticInfoById(userId);
        User user = userMapper.selectByUserId(userId);
        if (user==null){
            throw new CommonException(ResponseCodeEnum.CODE_603);
        }
        if (autheticInfo!=null){
            user.setRealName(autheticInfo.getRealname().substring(0, 1)+"*".repeat(autheticInfo.getRealname().length() - 1));
            user.setCodeID(autheticInfo.getCardId().substring(0,1)+"*".repeat(16)+autheticInfo.getCardId().substring(autheticInfo.getCardId().length() - 1));
        }
        return user;
    }

    @Override
    public User selectByUserOpenid(String userOpenid) {
        User user = userMapper.selectByUserOpenid(userOpenid);
        if (user!=null){
            user = userMapper.selectByUserId(user.getId());
        }else {
            return null;
        }
        AutheticInfo autheticInfo = autheticInfoService.selectAutheticInfoById(user.getId());
        if (user!=null&&autheticInfo!=null){
            user.setRealName(autheticInfo.getRealname().substring(0, 1)+"*".repeat(autheticInfo.getRealname().length() - 1));
            user.setCodeID(autheticInfo.getCardId().substring(0,1)+"*".repeat(16)+autheticInfo.getCardId().substring(autheticInfo.getCardId().length() - 1));

        }
        return user;
    }

    @Override
    public User insert(User newUser) {
        int insert = userMapper.insert(newUser);
        return newUser;
    }

    @Override
    public Page<User> selectFriendList(Page<User> userPage, Long userId) {
        return userMapper.selectFriendList(userPage,userId);
    }

    @Override
    public Page<User> selectFollowList(Page<User> userPage, Long userId) {
        return userMapper.selectFollowList(userPage,userId);
    }

    @Override
    public FriFolFan selectFansList(Page<User> userPage, Long userId) {
        FriFolFan friFolFan = new FriFolFan();
        Integer unReadFansCount = userMapper.unReadFansCount(userId);
        Page<User> page = userMapper.selectFansList(userPage, userId);
        page.getRecords().forEach(user -> {
            Integer integer = userMapper.selectIsFocus(userId, user.getId());
            if (integer!=0)
                user.setIsFollowed(true);
            else
                user.setIsFollowed(false);
        });
        friFolFan.setPage(page);
        friFolFan.setUnReadCount(unReadFansCount);
        return friFolFan;
    }

    @Override
    public FriFolFan seenMeList(Page<User> userPage, Long userId) {
        FriFolFan friFolFan = new FriFolFan();
        Integer unReadVisitCount = userMapper.unReadVisitCount(userId);
        Page<User> page = userMapper.seenMeList(userPage, userId);
        friFolFan.setPage(page);
        friFolFan.setUnReadCount(unReadVisitCount);
        return friFolFan;
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public int updateUser(User user) {
        return userMapper.updateById(user);
    }

    @Override
    public User registerByEmail(String email, String emailCode, String password) {
        QueryWrapper<User> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("email",email);
        if (userMapper.selectOne(queryWrapper)!=null){
            throw new RuntimeException("邮箱已经存在");
        }
        emailCodeService.checkCode(email,emailCode);
        User user = new User();
        user.setEmail(email);
        user.setPassword(SecretUtil.encrypt(password));
        user.setNickname("单身汪");
        user.setAvator(defaultAvatar);
        int insert = userMapper.insert(user);
        taohuaDetailService.insertTaohuaDetail(TaoHuaConstant.Type_1,user.getId());
        if (insert!=0){
            return user;
        }
        else {
            throw new CommonException("注册失败");
        }
    }

    @Override
    public User loginByEmail(String email, String password) {
        User user = userMapper.loginByEmail(email,password);
        if (user==null){
            throw new CommonException("邮箱或密码错误");
        }
        return user;
    }

    @Override
    public HashMap<String, Boolean> selectEverydayTask(Long id) {
        int publishCount = articleMapper.selectIsPublishInToday(id);
        int likeCount = likeMapper.selectIsLikeInToday(id);
        int commentCount = commentMapper.selectIsCommentInToday(id);
        HashMap<String, Boolean> map = new HashMap<>();
        map.put("isPublish",publishCount==0?false:true);
        map.put("isLike",likeCount==0?false:true);
        map.put("isComment",commentCount==0?false:true);
        return map;
    }

    @Override
    public Page<User> selectAllUser(Page<User> userPage) {
        return userMapper.selectPageUser(userPage);
    }

    @Override
    public Page getUserCommentLikeData(Long id, Integer pageNum, Integer pageSize) {
        //得到评论userid的
        Page<Article> articlePage = articleMapper.selectArticleListByUserId(new Page<Article>(pageNum, pageSize), id);
        List<UserCommentLikeDTO> result = new ArrayList<>();
        for (Article article : articlePage.getRecords()) {
            List<Comment> comments = commentMapper.getCommentsByArticleId(article.getId()); //评论文章的
            List<Comment> replayComment = commentMapper.getReplayComment(id, article.getId());
            List<Like> likes = likeMapper.getLikesByArticleId(article.getId());
            likes.addAll(likeMapper.getLikesCommentByArticleId(id));
            for (Comment comment : comments) {  //评论
                if (comment.getUserId().equals(id))continue; //过滤自己评论的
                UserCommentLikeDTO dto = new UserCommentLikeDTO();
                dto.setType(1); //评论
                dto.setArticleId(article.getId());
                dto.setArticleTitle(article.getContent());
                String image = articleMapper.selectArticleFirstImage(article.getId());
                if (image!=null){
                    dto.setArticleImageUrl(image);
                }
                dto.setCommentId(comment.getId());
                dto.setCommentContent(comment.getContent());
                dto.setCreateTime(comment.getCreateTime());

                User user = userMapper.selectByUserId(comment.getUserId());
                dto.setUser(user);
                result.add(dto);
            }
            for (Like like : likes) {
                if (like.getUserId().equals(id))continue; //过滤自己点赞
                UserCommentLikeDTO dto = new UserCommentLikeDTO();
                dto.setType(2); //点赞
                dto.setArticleId(article.getId());
                dto.setArticleTitle(article.getContent());
                String image = articleMapper.selectArticleFirstImage(article.getId());
                if (image!=null){
                    dto.setArticleImageUrl(image);
                }
                dto.setCreateTime(like.getCreateTime());
                User user = userMapper.selectByUserId(like.getUserId());
                dto.setUser(user);
                result.add(dto);
            }
            for (Comment comment : replayComment) {
                if (comment.getUserId().equals(id))continue; //过滤回复自己的
                UserCommentLikeDTO dto = new UserCommentLikeDTO();
                dto.setType(3);//回复
                dto.setArticleId(article.getId());
                dto.setArticleTitle(article.getContent());
                String image = articleMapper.selectArticleFirstImage(article.getId());
                if (image!=null){
                    dto.setArticleImageUrl(image);
                }
                dto.setCommentId(comment.getId());
                dto.setReplyContent(comment.getContent());
                dto.setCreateTime(comment.getCreateTime());
                User user = userMapper.selectByUserId(comment.getUserId());
                dto.setUser(user);
                result.add(dto);
            }
        }
        // 按照时间排序
        result.sort(Comparator.comparing(UserCommentLikeDTO::getCreateTime).reversed());
        Page<UserCommentLikeDTO> page = new Page<>();
        page.setTotal(articlePage.getTotal());
        page.setSize(articlePage.getSize());
        page.setCurrent(articlePage.getCurrent());
        page.setPages(articlePage.getPages());
        page.setRecords(result);
        return page;
    }

    @Override
    public Page<User> seenOtherList(Page<User> userPage, Long userId) {
        Page<User> page = userMapper.seenOtherList(userPage, userId);
        for (User user : page.getRecords()) {
            user.setSaw(true);
        }
        return page;
    }


    @Transactional(rollbackFor = Exception.class)
    @Override
    public void updateUserStatus(Long id, Integer status) {
        status = status==0?1:0;
        int cstatus = status;
        User user = new User();
        user.setId(id);
        user.setStatus((byte) cstatus);
        userMapper.updateById(user);
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void deleteUserById(Long id) {
        userMapper.deleteById(id);
    }

    /**
     * 根据标签获取相似的用户
     * @param pageNum
     * @param pageSize
     * @param loginId
     * @param max
     * @return
     */
    @Override
    public Page<Long> getSimilarUser(Integer pageNum,Integer pageSize,Long loginId,Integer max){
        List<Tags> tags = tagsService.selectUserTagsByUserId(loginId);
        List<String> tagList = tags.stream().map(item -> item.getTagName()).collect(Collectors.toList());
        QueryWrapper<User> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("is_hide",0); //未隐身的用户
        Page<User> userPage = userMapper.selectPage(new Page<User>(pageNum, pageSize), queryWrapper);  //查询用户的标签
        // 用户列表的下标 => 相似度
        List<Pair<User, Double>> list = new ArrayList<>();
        List<User> userList = userPage.getRecords();
        for (int i=0; i<userList.size();i++){
            User user = userList.get(i);
            List<Tags> userTags = tagsService.selectUserTagsByUserId(user.getId());
            if (tags.size()==0||user.getId()==loginId){  //排除自己 与 无标签
                continue;
            }
            List<String> userTagList = userTags.stream().map(item -> item.getTagName()).collect(Collectors.toList());
//            计算分数
            double similarity = CosineSimilarityUtil.cosineSimilarity(tagList, userTagList);
            if(Double.isNaN(similarity)){
                similarity=0;
            }
            list.add(new Pair<>(user, similarity));
        }
        // 按编辑距离由小到大排序
//        List<Pair<User, Double>> topUserPairList = list.stream()
//                .sorted((a, b) -> Double.compare(b.getValue(), a.getValue()))
//                .collect(Collectors.toList()).subList(0,max);

        List<Pair<User, Double>> topUserPairList = list.stream()
                .sorted((a, b) -> Double.compare(b.getValue(), a.getValue()))
                .collect(Collectors.toList());

        int size = Math.min(max, topUserPairList.size());
        topUserPairList = topUserPairList.subList(0, size);
        // 获取原本顺序的 userId 列表
        List<Long> userIdList = topUserPairList.stream().map(pair -> pair.getKey().getId()).collect(Collectors.toList());
        Page<Long> page = new Page<>();
        page.setPages(userPage.getPages());
        page.setCurrent(pageNum);
        page.setRecords(userIdList);
        return page;
    }


    /**
     * 根据用户id批量获取用户
     * @param ids
     * @return
     */
    @Override
    public List<User> getUserListByIds(List<Long> ids) {
        QueryWrapper<User> userQueryWrapper = new QueryWrapper<>();
        userQueryWrapper.in("id", ids);
        List<User> users = userMapper.selectList(userQueryWrapper);
        return users;
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public Page CosmatchUsers(Long id,Integer pageNum,Integer pageSize) {
        int matchNum = matchService.getMatchNum(id);
        if (matchNum>=5){
            throw new CommonException("今日速配次数已用完");
        }

        Page<User> page = new Page<User>(pageNum,pageSize);
        // 得到当前登录的用户
        User curUser = userMapper.selectUser(id);
        Byte sex = curUser.getSex();
        // 偏好
        Preference preference = preferenceService.selectPreferenceByUserId(id);
        //标签
        List<Tags> curUserTags = tagsService.selectUserTagsByUserId(curUser.getId());
        List<String> tagList = curUserTags.stream().map(item -> item.getTagName()).collect(Collectors.toList());
        //筛选
        QueryWrapper<User> queryWrapper = new QueryWrapper<>();
        //性别
        queryWrapper.eq("sex",sex.byteValue()==0?1:0);
        //匹配过的用户
        List<Long> matchedUserId = matchService.selectMatchedUserId(curUser.getId());
        queryWrapper.notIn(matchedUserId.size()!=0,"id",matchedUserId);
        if (preference!=null){
        queryWrapper.nested(i->i.between("height",preference.getMinHeight(),preference.getMaxHeight())
                .or(j->j.eq("education",preference.getEducation()))
                .or(k->k.apply("YEAR(birthday) BETWEEN {0} AND {1}",preference.getMinAge(),preference.getMaxAge()))
                .or(x->x.eq("education",preference.getEducation())));
        }
        Page<User> userPage = userMapper.selectPage(page, queryWrapper);
//        if (userPage.getRecords().size()==0){
//            //重新查询 或者另外的策略
//            QueryWrapper condition = new QueryWrapper<>().eq("sex",sex.byteValue()==0?1:0);
//            userPage = userMapper.selectPage(page,condition);
//        }
        List<Pair<User, Double>> list = new ArrayList<>();
        //根据标签依次计算所有用户和当前用户的相似度
        List<User> userList = userPage.getRecords();
        for (int i = 0; i < userList.size(); i++){
            User user = userList.get(i);
            List<Tags> tags = tagsService.selectUserTagsByUserId(user.getId());
            if (tags.size()==0||user.getId()==curUser.getId()){  //排除自己 与 无标签
                continue;
            }
            List<String> userTagList = tags.stream().map(item -> item.getTagName()).collect(Collectors.toList());
//            计算分数
            double similarity = CosineSimilarityUtil.cosineSimilarity(tagList, userTagList);
            if(Double.isNaN(similarity)){
                similarity=0;
            }
//            同城优先
            if (preference.getCityType().equals(1)&&user.getLocation().equals(curUser.getLocation())){
                similarity += 0.5;
            }
            if (user.getProfessionId()!=null&&curUser.getProfessionId()!=null&&user.getProfessionId().equals(curUser.getProfessionId())){
                similarity += 0.5;
            }
            list.add(new Pair<>(user, similarity));
        }
        // 使用Stream API表达式对列表中的Pair对象按照Double类型的值进行降序排序
        List<Pair<User, Double>> topUserPairList = list.stream()
                .sorted((a, b) -> Double.compare(b.getValue(), a.getValue()))
                .collect(Collectors.toList());
        if (topUserPairList.size()!=0){
            User user = topUserPairList.get(0).getKey();
            List<User> users = new ArrayList<>();
            users.add(user);
            matchService.insertMatchUser(curUser.getId(),user.getId());
            Message message = new Message();
            message.setContent("匹配成功，开始聊天吧 ~");
            message.setFrom(curUser.getId());
            message.setTo(user.getId());
            message.setType(1);
            message.setIsRead(false);
            messageService.addMessage(message);
            return userPage.setRecords(users);
        }
        // 查询
        log.info("err---------err---------未查到用户");
//        QueryWrapper condition = new QueryWrapper<>().eq("sex",sex.byteValue()==0?1:0);
//        userPage = userMapper.selectPage(page,condition);
        return userPage;
    }


    @Override
    public void updateNotice(Long id, Integer noticeType) {
        User user = new User();
        user.setId(id);
        int type = noticeType;
        user.setNotice((byte) type);
        userMapper.updateById(user);
    }

    @Override
    public void updateHide(Long id, Integer hideType) {
        User user = new User();
        user.setId(id);
        if (hideType.equals(0)){
            user.setIsHide(false);
        }else {
            user.setIsHide(true);
        }
        userMapper.updateById(user);
    }

    @Override
    public void logOff(Long id) {
        userMapper.deleteById(id);
    }


    @Transactional(rollbackFor = Exception.class)
    @Override
    public void updateReaction(Long id) {
        likeMapper.updateUnreadLIkeInArticleLike(id);
        likeMapper.updateUnreadLIkeInReplayComment(id);
        commentMapper.updateUnreadCountCommentByArticleId(id);
        commentMapper.updateUnreadCommentInReplayComment(id);
    }

    @Override
    public HashMap<String, Object> getScreenNav() {
        Long totalUser = userMapper.selectCount(null);
        Long totalWish = bulletMapper.selectCount(null);
        Integer todayMatch = matchService.getMatchNum();
        Integer totalMatch = matchService.getTotalNum();
        HashMap<String, Object> map = new HashMap<>();
        map.put("totalUser",totalUser);
        map.put("totalWish",totalWish);
        map.put("todayMatch",todayMatch);
        map.put("totalMatch",totalMatch);
        return map;
    }

    @Override
    public List<MatchDto> getScreenMatch() {
        ArrayList<MatchDto> matchDtos = matchMapper.selectWeekMatch();

        // 创建一个长度为7的ArrayList
        List<MatchDto> data = new ArrayList<>();

        // 获取最近一周的日期，并添加到ArrayList中
        Calendar calendar = Calendar.getInstance();
        SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");

        for (int i = 0; i < 7; i++) {
            // 创建一个HashMap来存储日期和对应的int值
            MatchDto matchDto = new MatchDto();
            matchDto.setMatchCount(0);
            matchDto.setDate(dateFormat.format(calendar.getTime()));
            data.add(matchDto);
            // 将日期往前推一天
            calendar.add(Calendar.DAY_OF_YEAR, -1);
        }

        for (MatchDto datum : data) {
            for (MatchDto matchDto : matchDtos) {
                if (datum.getDate().equals(matchDto.getDate())){
                    datum.setMatchCount(matchDto.getMatchCount());
                    break;
                }
            }
        }

        return data;
    }
}
